{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "# Flask 模板\r\n",
    "\r\n",
    "到目前为止，我们一直直接在视图函数中硬编码 HTML 字符串。虽然这种方法对于演示目的来说是很好的，但是对于构建真实的应用程序来说就不那么适合了。现在大多数网页都很长，并且由许多动态组件组成。我们使用模板，而不是在视图函数中嵌入大块的 HTML 字符串(维护起来会很糟糕)。\r\n",
    "\r\n",
    "## `Templates` 模板\r\n",
    "\r\n",
    "模板只是一个文本文件，其中包含静态 HTML 代码以及一些特殊的标记，表示在请求时将知道的动态内容。取代动态标记并生成扁平 HTML 页面的过程称为模板呈现。\r\n",
    "\r\n",
    "Flask 与一个名为 `Jinja`  的模板引擎捆绑在一起，该引擎完成了解析模板并将其转换为扁平 HTML 页面的实际工作。\r\n",
    "\r\n",
    "`Jinja` 模板引擎是 Python 中最强大和最流行的模板引擎之一。如果你曾经使用过 Django 模板，那么你会有宾至如归的感觉。值得注意的是，`Jinja` 和 `Flask` 是两个独立的包，可以单独使用。\r\n",
    "\r\n",
    "##  使用 render_template() 渲染模板\r\n",
    "\r\n",
    "默认情况下，Flask 在应用程序文件夹中名为 `templates` 的子目录中查找模板。我们可以通过在创建应用程序实例时将 `template_folder` 参数传递给 Flask 构造函数来更改这种默认行为。\r\n",
    "\r\n",
    "`app = Flask(__name__, template_folder=\"jinja_templates\")`\r\n",
    "\r\n",
    "目前，我们没有任何理由这样做，因此我们将继续使用默认模板目录来存储模板。\r\n",
    "\r\n",
    "在 flask_app  应用程序目录中创建一个名为 `templates` 的新目录。在模板目录中创建一个名为 index.html 的模板，代码如下:\r\n",
    "\r\n",
    "### flask_app/templates/index.html\r\n",
    "```html\r\n",
    "<!DOCTYPE html>\r\n",
    "<html lang=\"en\">\r\n",
    "<head>\r\n",
    "    <meta charset=\"UTF-8\">\r\n",
    "    <title>Title</title>\r\n",
    "</head>\r\n",
    "<body>\r\n",
    "\r\n",
    "    <p>Name: {{ name }}</p>\r\n",
    "\r\n",
    "</body>\r\n",
    "</html>\r\n",
    "```\r\n",
    "\r\n",
    "请注意，除了基本的 HTML 之外，模板还有一个标记为{ name }的动态组件。双花括号{{}中的名称代表一个变量，其值将在呈现模板时指定。假设 name 的值是 Jerry，那么在渲染模板之后，您将得到以下 HTML。\r\n",
    "\r\n",
    "### flask_app/templates/index_after_render.html\r\n",
    "```html\r\n",
    "<!DOCTYPE html>\r\n",
    "<html lang=\"en\">\r\n",
    "<head>\r\n",
    "    <meta charset=\"UTF-8\">\r\n",
    "    <title>Title</title>\r\n",
    "</head>\r\n",
    "<body>\r\n",
    "\r\n",
    "    <p>Name: Jerry</p>\r\n",
    "\r\n",
    "</body>\r\n",
    "</html>\r\n",
    "```"
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "Flask 提供了一个函数，称为 `render_template()` ，用于呈现模板。正是这种功能使jinja与Flask相结合。要呈现一个模板，我们调用 `render_template()` ，其中包含模板名称以及作为关键字参数传递给模板的数据。函数的作用是: 渲染模板，并以字符串的形式返回 HTML。我们传递给模板的关键字参数称为 模板上下文(the context of the template) 或 简单的模板上下文(simply template context)。下面的清单显示了如何使用 `render_template()` 呈现索引 .html 模板。\r\n",
    "\r\n",
    "### flask_app/main2.py\r\n",
    "\r\n",
    "```python\r\n",
    "from flask import Flask, request, render_template\r\n",
    "app = Flask(__name__)\r\n",
    "\r\n",
    "@app.route('/')\r\n",
    "def index():\r\n",
    "    return render_template('index.html', name='Jerry')\r\n",
    "#...\r\n",
    "```\r\n",
    "\r\n",
    "注意 name = ‘ Jerry’中的 name 指的是模板索引.html 中引用的变量。\r\n",
    "\r\n",
    "如果你现在访问 http://localhost:5000/ ，你会得到如下回复:\r\n",
    "\r\n",
    "![img](https://overiq.com/media/uploads/2018/1/8/rendering_template_using_render_template-971f582d-b137-4b3c-b499-0bbe5243e000.png)\r\n",
    "\r\n"
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "如果有很多参数需要传递给 render_template() ，那么不要使用逗号(,)分隔它们，而是创建一个字典并在其上应用 ** 操作符，以便将关键字参数传递给函数。例如:\r\n",
    "\r\n",
    "### flask_app/main2_**template_context.py\r\n",
    "\r\n",
    "```\r\n",
    "@app.route('/')\r\n",
    "def index():\r\n",
    "    name, age, profession = \"Jerry\", 24, 'Programmer'\r\n",
    "    template_context = dict(name=name, age=age , profession=profession)\r\n",
    "    return render_template('index.html', **template_context)\r\n",
    "```\r\n",
    "\r\n",
    "索引模板现在可以访问三个模板变量: 名称、年龄和职业。\r\n",
    "\r\n",
    "如果不指定模板上下文会发生什么？\r\n",
    "\r\n",
    "什么都不会发生，你不会得到任何警告或异常，金贾会像往常一样呈现模板，代替变量的空字符串将被打印。要查看此行为的实际操作，请按如下方式修改 index ()视图函数:\r\n",
    "\r\n",
    "### flask_app/main2.py\r\n",
    "\r\n",
    "```\r\n",
    "#...\r\n",
    "@app.route('/')\r\n",
    "def index():\r\n",
    "    return render_template('index.html')\r\n",
    "#...\r\n",
    "```\r\n",
    "访问 google http://localhost:5000/ ，这次你会得到如下的 HTML 回复:\r\n",
    "\r\n",
    "\r\n",
    "```html\r\n",
    "<!DOCTYPE html>\r\n",
    "<html lang=\"en\">\r\n",
    "<head>\r\n",
    "    <meta charset=\"UTF-8\">\r\n",
    "    <title>Title</title>\r\n",
    "</head>\r\n",
    "<body>\r\n",
    "\r\n",
    "    <p>Name: </p>\r\n",
    "\r\n",
    "</body>\r\n",
    "</html>\r\n",
    "```\r\n",
    "\r\n",
    "现在您应该对模板在 Flask 中的使用有了一个大致的了解，下一节将展示如何在控制台中渲染模板。"
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 在控制台中渲染模板\r\n",
    "\r\n",
    "在控制台中测试渲染模板非常简单，而不需要创建多个文件。从 jinja2包启动 Python shell 并导入 Template 类，如下所示。\r\n",
    "\r\n",
    "要创建 Template 对象，只需将模板的内容作为原始字符串传递。\r\n",
    "\r\n",
    "呈现 Template 对象的模板调用 render ()方法以及作为关键字参数的数据。"
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "source": [
    "from jinja2 import Template\r\n",
    "t = Template(\"Name: {{ name }}\")\r\n",
    "t.render(name='Jerry')"
   ],
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "'Name: Jerry'"
      ]
     },
     "metadata": {},
     "execution_count": 1
    }
   ],
   "metadata": {}
  }
 ],
 "metadata": {
  "orig_nbformat": 4,
  "language_info": {
   "name": "python",
   "version": "3.9.6",
   "mimetype": "text/x-python",
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "pygments_lexer": "ipython3",
   "nbconvert_exporter": "python",
   "file_extension": ".py"
  },
  "kernelspec": {
   "name": "python3",
   "display_name": "Python 3.9.6 64-bit"
  },
  "interpreter": {
   "hash": "c644d696b95f5e0f4df3c6556741cf30bcf9ea6ca93c3e1f29fcf31d885534fc"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}